package top.hcode.hoj.utils;

import lombok.Getter;

/**
 * @Author: Himit_ZH
 * @Date: 2021/1/1 13:00
 * @Description: 常量枚举类
 */
public class Constants {

    /**
     * @Description 提交评测结果的状态码
     * @Since 2021/1/1
     */
    public enum Judge {
        STATUS_NOT_SUBMITTED(-10, "Not Submitted", null),
        STATUS_SUBMITTED_UNKNOWN_RESULT(-5, "Submitted Unknown Result", null),
        STATUS_CANCELLED(-4, "Cancelled", "ca"),
        STATUS_PRESENTATION_ERROR(-3, "Presentation Error", "pe"),
        STATUS_COMPILE_ERROR(-2, "Compile Error", "ce"),
        STATUS_WRONG_ANSWER(-1, "Wrong Answer", "wa"),
        STATUS_ACCEPTED(0, "Accepted", "ac"),
        STATUS_TIME_LIMIT_EXCEEDED(1, "Time Limit Exceeded", "tle"),
        STATUS_MEMORY_LIMIT_EXCEEDED(2, "Memory Limit Exceeded", "mle"),
        STATUS_RUNTIME_ERROR(3, "Runtime Error", "re"),
        STATUS_SYSTEM_ERROR(4, "System Error", "se"),
        STATUS_PENDING(5, "Pending", null),
        STATUS_COMPILING(6, "Compiling", null),
        STATUS_JUDGING(7, "Judging", null),
        STATUS_PARTIAL_ACCEPTED(8, "Partial Accepted", "pa"),
        STATUS_SUBMITTING(9, "Submitting", null),
        STATUS_SUBMITTED_FAILED(10, "Submitted Failed", null),
        STATUS_NULL(15, "No Status", null),
        JUDGE_SERVER_SUBMIT_PREFIX(-1002, "Judge SubmitId-ServerId:", null);

        private Judge(Integer status, String name, String columnName) {
            this.status = status;
            this.name = name;
            this.columnName = columnName;
        }

        private final Integer status;
        private final String name;
        private final String columnName;

        public Integer getStatus() {
            return status;
        }

        public String getName() {
            return name;
        }

        public String getColumnName() {
            return columnName;
        }

        public static Judge getTypeByStatus(int status) {
            for (Judge judge : Judge.values()) {
                if (judge.getStatus() == status) {
                    return judge;
                }
            }
            return STATUS_NULL;
        }
    }

    public enum RemoteJudge {

        LUOGU_JUDGE("LUOGU"),
        HDU_JUDGE("HDU"),

        CF_JUDGE("CF"),

        GYM_JUDGE("GYM"),

        POJ_JUDGE("POJ"),

        SPOJ_JUDGE("SPOJ"),

        ATCODER_JUDGE("AC"),

        LIBRE_JUDGE("LIBRE"),

        HDU_REMOTE_JUDGE_ACCOUNT("Hdu Remote Judge Account"),

        CF_REMOTE_JUDGE_ACCOUNT("Codeforces Remote Judge Account");

        private final String name;

        RemoteJudge(String remoteJudgeName) {
            this.name = remoteJudgeName;
        }

        public static RemoteJudge getTypeByName(String judgeName) {
            if (judgeName == null) return null;
            for (RemoteJudge remoteJudge : RemoteJudge.values()) {
                if (remoteJudge.getName().equals(judgeName)) {
                    return remoteJudge;
                }
            }
            return null;
        }

        public static String getListNameByOJName(String judgeName) {
            if (judgeName == null) return null;
            switch (judgeName) {
                case "HDU":
                    return RemoteJudge.HDU_REMOTE_JUDGE_ACCOUNT.getName();
                case "CF":
                    return RemoteJudge.CF_REMOTE_JUDGE_ACCOUNT.getName();
            }
            return null;
        }

        public String getName() {
            return name;
        }
    }

    /**
     * 等待判题的redis队列
     *
     * @Since 2021/12/22
     */
    public enum Queue {
        CONTEST_JUDGE_WAITING("Contest_Waiting_Handle_Queue"),
        GENERAL_JUDGE_WAITING("General_Waiting_Handle_Queue"),
        TEST_JUDGE_WAITING("Test_Judge_Waiting_Handle_Queue"),
        CONTEST_REMOTE_JUDGE_WAITING_HANDLE("Contest_Remote_Waiting_Handle_Queue"),
        GENERAL_REMOTE_JUDGE_WAITING_HANDLE("General_Remote_Waiting_Handle_Queue");

        private Queue(String name) {
            this.name = name;
        }

        private final String name;

        public String getName() {
            return name;
        }
    }

    private static final int DAY_SECONDS = 3600 * 24;

    @Getter
    public enum RemoteOJ {

        LUOGU("洛谷", DAY_SECONDS * 28),
        HDU("HDU", DAY_SECONDS * 7),
        CODEFORCES("CF", DAY_SECONDS * 7),
        GYM("GYM", DAY_SECONDS * 7),
        POJ("POJ", DAY_SECONDS * 7),
        SPOJ("SPOJ", DAY_SECONDS * 7),
        AC("AtCoder", DAY_SECONDS * 7),
        LIBRE("LIBRE", DAY_SECONDS * 7);

        private final String label;

        private final int cookieAge;   // 登录后cookie有效期，单位为秒


        RemoteOJ(String label, int cookieAge) {
            this.label = label;
            this.cookieAge = cookieAge;
        }

        public static Boolean isRemoteOJ(String name) {
            for (RemoteOJ remoteOJ : RemoteOJ.values()) {
                if (remoteOJ.name().equals(name) || remoteOJ.label.equalsIgnoreCase(name)) {
                    return true;
                }
            }
            return false;

        }

        public static RemoteOJ getRemoteOJ(String name) {
            for (RemoteOJ remoteOJ : RemoteOJ.values()) {
                if (remoteOJ.name().equals(name) || remoteOJ.getLabel().equals(name)) {
                    return remoteOJ;
                }
            }
            return null;
        }
    }


    /**
     * @Description 比赛相关的常量
     * @Since 2021/1/7
     */
    public enum Contest {
        TYPE_ACM(0, "ACM"),
        TYPE_OI(1, "OI"),

        STATUS_SCHEDULED(-1, "Scheduled"),
        STATUS_RUNNING(0, "Running"),
        STATUS_ENDED(1, "Ended"),

        AUTH_PUBLIC(0, "Public"),
        AUTH_PRIVATE(1, "Private"),
        AUTH_PROTECT(2, "Protect"),

        RECORD_NOT_AC_PENALTY(-1, "未AC通过算罚时"),
        RECORD_NOT_AC_NOT_PENALTY(0, "未AC通过不罚时"),
        RECORD_AC(1, "AC通过"),

        OI_CONTEST_RANK_CACHE(null, "oi_contest_rank_cache"),

        CONTEST_RANK_CAL_RESULT_CACHE(null, "contest_rank_cal_result_cache"),

        OI_RANK_RECENT_SCORE(null, "Recent"),
        OI_RANK_HIGHEST_SCORE(null, "Highest");

        private final Integer code;
        private final String name;

        Contest(Integer code, String name) {
            this.code = code;
            this.name = name;
        }

        public Integer getCode() {
            return code;
        }

        public String getName() {
            return name;
        }
    }

    /**
     * @Description 账户相关常量
     * @Since 2021/1/8
     */
    public enum Account {
        CODE_CHANGE_PASSWORD_FAIL("change-password-fail:"),
        CODE_CHANGE_PASSWORD_LOCK("change-password-lock:"),
        CODE_ACCOUNT_LOCK("account-lock:"),
        CODE_CHANGE_EMAIL_FAIL("change-email-fail:"),
        CODE_CHANGE_EMAIL_LOCK("change-email-lock:"),

        TRY_LOGIN_NUM("try-login-num:"),

        ACM_RANK_CACHE("acm_rank_cache"),
        OI_RANK_CACHE("oi_rank_cache"),

        GROUP_RANK_CACHE("group_rank_cache"),

        SUPER_ADMIN_UID_LIST_CACHE("super_admin_uid_list_case"),

        SUBMIT_NON_CONTEST_LOCK("submit_non_contest_lock:"),
        TEST_JUDGE_LOCK("test_judge_lock:"),
        SUBMIT_CONTEST_LOCK("submit_contest_lock:"),
        DISCUSSION_ADD_NUM_LOCK("discussion_add_num_lock:"),
        GROUP_ADD_NUM_LOCK("group_add_num_lock"),
        CONTEST_ADD_PRINT_LOCK("contest_add_print_lock:"),

        REMOTE_JUDGE_CF_ACCOUNT_NUM("remote_judge_cf_account:");

        private final String code;

        Account(String code) {
            this.code = code;
        }

        public String getCode() {
            return code;
        }
    }


    /**
     * @Description 文件操作的一些常量
     * @Since 2021/1/10
     */
    public enum File {


        USER_AVATAR_FOLDER("/hoj/file/avatar"),

        GROUP_AVATAR_FOLDER("/hoj/file/avatar/group"),

        HOME_CAROUSEL_FOLDER("/hoj/file/carousel"),

        MARKDOWN_FILE_FOLDER("/hoj/file/md"),

        PROBLEM_FILE_FOLDER("/hoj/file/problem"),

        CONTEST_TEXT_PRINT_FOLDER("/hoj/file/contest_print"),

        IMG_API("/api/public/img/"),

        FILE_API("/api/public/file/"),

        TESTCASE_TMP_FOLDER("/hoj/file/zip"),

        TESTCASE_BASE_FOLDER("/hoj/testcase"),

        FILE_DOWNLOAD_TMP_FOLDER("/hoj/file/zip/download"),

        CONTEST_AC_SUBMISSION_TMP_FOLDER("/hoj/file/zip/contest_ac");

        private final String path;

        File(String path) {
            this.path = path;
        }

        public String getPath() {
            return path;
        }
    }


    /**
     * @Description 邮件任务的一些常量
     * @Since 2021/1/14
     */

    public enum Email {

        OJ_URL("OJ_UR"),
        OJ_NAME("OJ_NAME"),
        OJ_SHORT_NAME("OJ_SHORT_NAME"),
        EMAIL_FROM("EMAIL_FROM"),
        EMAIL_BACKGROUND_IMG("EMAIL_BACKGROUND_IMG"),
        REGISTER_KEY_PREFIX("register-user:"),
        CHANGE_EMAIL_KEY_PREFIX("change-email:"),
        RESET_PASSWORD_KEY_PREFIX("reset-password:"),
        RESET_EMAIL_LOCK("reset-email-lock:"),
        REGISTER_EMAIL_LOCK("register-email-lock:"),
        CHANGE_EMAIL_LOCK("change-email-lock:");

        private final String value;

        Email(String value) {
            this.value = value;
        }

        public String getValue() {
            return value;
        }
    }

    public enum Schedule {
        RECENT_OTHER_CONTEST("recent-other-contest");

        private final String code;

        Schedule(String code) {
            this.code = code;
        }

        public String getCode() {
            return code;

        }
    }

    /**
     * @Description 训练题单的一些常量
     * @Since 2021/11/20
     */
    public enum Training {

        AUTH_PRIVATE("Private"),
        AUTH_PUBLIC("Public");

        private final String value;

        Training(String value) {
            this.value = value;
        }

        public String getValue() {
            return value;
        }
    }

    public enum ProblemType {
        ACM(0),
        OI(1);
        private final Integer type;

        ProblemType(Integer type) {
            this.type = type;
        }

        public Integer getType() {
            return type;
        }

        public static ProblemType getProblemType(Integer type) {
            for (ProblemType problemType : ProblemType.values()) {
                if (problemType.getType().equals(type)) {
                    return problemType;
                }
            }
            return null;
        }
    }

    public enum ProblemAuth {
        PUBLIC(1),
        PRIVATE(2),
        CONTEST(3);

        private final Integer auth;

        ProblemAuth(Integer auth) {
            this.auth = auth;
        }

        public Integer getAuth() {
            return auth;
        }

        public static ProblemAuth getProblemAuth(Integer auth) {
            for (ProblemAuth problemAuth : ProblemAuth.values()) {
                if (problemAuth.getAuth().equals(auth)) {
                    return problemAuth;
                }
            }
            return null;
        }
    }

    public enum JudgeMode {
        TEST("test"),

        DEFAULT("default"),
        SPJ("spj"),
        INTERACTIVE("interactive");

        private final String mode;

        JudgeMode(String mode) {
            this.mode = mode;
        }

        public String getMode() {
            return mode;
        }

        public static JudgeMode getJudgeMode(String mode) {
            for (JudgeMode judgeMode : JudgeMode.values()) {
                if (judgeMode.getMode().equals(mode)) {
                    return judgeMode;
                }
            }
            return null;
        }
    }

    public enum JudgeCaseMode {
        DEFAULT("default"),
        SUBTASK_LOWEST("subtask_lowest"),
        SUBTASK_AVERAGE("subtask_average"),
        ERGODIC_WITHOUT_ERROR("ergodic_without_error");

        private final String mode;

        JudgeCaseMode(String mode) {
            this.mode = mode;
        }

        public String getMode() {
            return mode;
        }


        public static JudgeCaseMode getJudgeCaseMode(String mode) {
            for (JudgeCaseMode judgeCaseMode : JudgeCaseMode.values()) {
                if (judgeCaseMode.getMode().equals(mode)) {
                    return judgeCaseMode;
                }
            }
            return DEFAULT;
        }
    }

    public enum JudgeDir {

        RUN_WORKPLACE_DIR("/judge/run"),

        TEST_CASE_DIR("/judge/test_case"),

        SPJ_WORKPLACE_DIR("/judge/spj"),

        INTERACTIVE_WORKPLACE_DIR("/judge/interactive"),

        TMPFS_DIR("/w");


        private final String content;

        JudgeDir(String content) {
            this.content = content;
        }

        public String getContent() {
            return content;
        }
    }

    public enum TaskType {
        /**
         * 自身评测
         */
        JUDGE("/judge"),
        /**
         * 远程评测
         */
        REMOTE_JUDGE("/remote-judge"),

        /**
         * 在线调试
         */
        TEST_JUDGE("/test-judge"),
        /**
         * 编译特判程序
         */
        COMPILE_SPJ("/compile-spj"),

        /**
         * 编译交互程序
         */
        COMPILE_INTERACTIVE("/compile-interactive");

        private final String path;

        TaskType(String path) {
            this.path = path;
        }

        public String getPath() {
            return path;
        }

    }

    @Getter
    public enum QuestionType {
        // 习题类型：1：单选题，2：多选题，3：填空题，9：编程题
        SINGLE_CHOICE(1, "单选题"),
        MULTI_CHOICE(2, "多选题"),
        BLANK(3, "填空题"),
        SHORT_ANSWER(4, "简答题"),
        PROGRAM(9, "编程题"),
        UNKNOWN(99, "未知");


        private final Integer type;
        private final String label;

        QuestionType(Integer type, String label) {
            this.type = type;
            this.label = label;
        }

        public static QuestionType getQuestionType(Integer type) {
            for (QuestionType questionType : QuestionType.values()) {
                if (questionType.getType().equals(type)) {
                    return questionType;
                }
            }

            return UNKNOWN;
        }

        public static boolean isChoice(Integer value) {
            QuestionType type = getQuestionType(value);
            return type == SINGLE_CHOICE || type == MULTI_CHOICE;
        }
    }

    @Getter
    public enum StuffType {
        // dir 目录；video 视频；ppt；doc；image；md 在线文档；question_set 题单
        DIR("目录"),
        VIDEO("视频"),
        AUDIO("音频"),
        PPT("PPT"),
        DOC("文档"),
        IMAGE("图片"),
        MD("在线文档"),
        QUESTION_SET("题单"),
        OTHER("其他"),
        UNKNOWN("未知");
        private final String label;

        StuffType(String label) {
            this.label = label;
        }

        public static StuffType getStuffType(String type) {
            for (StuffType stuffType : StuffType.values()) {
                if (stuffType.name().equalsIgnoreCase(type)) {
                    return stuffType;
                }
            }

            return UNKNOWN;
        }
    }

    @Getter
    public enum OrgType {
        // 机构   学校   校区   部门   学段   年级   班级
        INSTITUTION(1, "机构"),
        SCHOOL(2, "学校"),
        CAMPUS(3, "校区"),
        DEPARTMENT(4, "部门"),
        SEMESTER(5, "学段"),
        GRADE(6, "年级"),
        CLASS(7, "班级"),
        ;
        private final Integer type;
        private final String label;

        OrgType(Integer type, String label) {
            this.type = type;
            this.label = label;
        }

        public static OrgType getOrgType(Integer type) {
            for (OrgType orgType : OrgType.values()) {
                if (orgType.getType().equals(type)) {
                    return orgType;
                }
            }
            return null;
        }
    }

    @Getter
    public enum UserType {
        STUDENT(0, "学生"),
        TEACHER(1, "教师"),
        UNKNOWN(-1, "未知"),
        ;
        private final Integer type;
        private final String label;

        UserType(Integer type, String label) {
            this.type = type;
            this.label = label;
        }

        public static UserType getUserType(Integer type) {
            for (UserType userType : UserType.values()) {
                if (userType.getType().equals(type)) {
                    return userType;
                }
            }
            return null;
        }
    }

    @Getter
    public enum HonorLevel {
        // 国家级、省级、市级、区级、校级
        NATION(0, "国家级"),
        PROVINCE(1, "省级"),
        CITY(2, "市级"),
        DISTRICT(3, "区级"),
        SCHOOL(4, "校级"),
        ;
        private final Integer level;
        private final String label;

        HonorLevel(Integer type, String label) {
            this.level = type;
            this.label = label;
        }

        public static HonorLevel getHonorLevel(Integer level) {
            for (HonorLevel honorLevel : HonorLevel.values()) {
                if (honorLevel.getLevel().equals(level)) {
                    return honorLevel;
                }
            }
            return null;
        }
    }

    @Getter
    public enum GradeNum {
        PRE_SCHOOL(0, "学前班"),
        GRADE_1(1, "一年级"),
        GRADE_2(2, "二年级"),
        GRADE_3(3, "三年级"),
        GRADE_4(4, "四年级"),
        GRADE_5(5, "五年级"),
        GRADE_6(6, "六年级"),
        MIDDLE_1(7, "初一"),
        MIDDLE_2(8, "初二"),
        MIDDLE_3(9, "初三"),
        HIGH_1(10, "高一"),
        HIGH_2(11, "高二"),
        HIGH_3(12, "高三");
        private final Integer value;
        private final String label;

        GradeNum(Integer value, String label) {
            this.value = value;
            this.label = label;
        }

        public static GradeNum getGradeClass(Integer value) {
            for (GradeNum gradeClass : GradeNum.values()) {
                if (gradeClass.getValue().equals(value)) {
                    return gradeClass;
                }
            }
            return null;
        }

        public static int parseGradeNum(String gradeName) {
            for (GradeNum gradeClass : GradeNum.values()) {
                if (gradeName.contains(gradeClass.getLabel())) {
                    return gradeClass.getValue();
                }
            }
            if (gradeName.contains("七年级") || gradeName.contains("初中一年级")) {
                return GradeNum.MIDDLE_1.getValue();
            } else if (gradeName.contains("八年级") || gradeName.contains("初中二年级")) {
                return GradeNum.MIDDLE_2.getValue();
            } else if (gradeName.contains("九年级") || gradeName.contains("初中三年级")) {
                return GradeNum.MIDDLE_3.getValue();
            } else if (gradeName.contains("十年级") || gradeName.contains("高中一年级")) {
                return GradeNum.HIGH_1.getValue();
            } else if (gradeName.contains("十一年级") || gradeName.contains("高中二年级")) {
                return GradeNum.HIGH_2.getValue();
            } else if (gradeName.contains("十二年级") || gradeName.contains("高中三年级")) {
                return GradeNum.HIGH_3.getValue();
            }

            throw new RuntimeException("无法解析的年级名称 ：" + gradeName);
        }

    }

    public static final String DEFAULT_COLL_ID = "1881687656945991683";
}